﻿using Core;
using Modbus.Device;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Management;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace DDS.IoT.Modbus
{
    public class ModbusHelper
    {
        /// <summary>
        /// 获取可用串口
        /// </summary>
        /// <returns></returns>
        public static List<string> GetCom()
        {
            List<string> coms = new List<string>();

            try
            {
                //搜索设备管理器中的所有条目
                using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from Win32_PnPEntity"))
                {
                    var hardInfos = searcher.Get();
                    foreach (var hardInfo in hardInfos)
                    {
                        if (hardInfo.Properties["Name"].Value != null)
                        {
                            if (hardInfo.Properties["Name"].Value.ToString().Contains("COM"))
                            {
                                coms.Add(hardInfo.Properties["Name"].Value.ToString());
                            }
                        }
                    }
                    searcher.Dispose();
                }

            }
            catch
            {
                return null;
            }

            return coms;
        }


        /// <summary>
        /// 判断数据中crc是否正确
        /// </summary>
        /// <param name="datas">传入的数据后两位是crc</param>
        /// <returns></returns>
        public static bool IsCrcOK(byte[] datas)
        {
            int length = datas.Length - 2;

            byte[] bytes = new byte[length];
            Array.Copy(datas, 0, bytes, 0, length);
            byte[] getCrc = GetModbusCrc16(bytes);

            if (getCrc[0] == datas[length] && getCrc[1] == datas[length + 1])
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 传入数据添加两位crc
        /// </summary>
        /// <param name="datas"></param>
        /// <returns></returns>
        public static byte[] GetCRCDatas(byte[] datas)
        {
            int length = datas.Length;
            byte[] crc16 = GetModbusCrc16(datas);
            byte[] crcDatas = new byte[length + 2];
            Array.Copy(datas, crcDatas, length);
            Array.Copy(crc16, 0, crcDatas, length, 2);
            return crcDatas;
        }
        private static byte[] GetModbusCrc16(byte[] bytes)
        {
            byte crcRegister_H = 0xFF, crcRegister_L = 0xFF;// 预置一个值为 0xFFFF 的 16 位寄存器

            byte polynomialCode_H = 0xA0, polynomialCode_L = 0x01;// 多项式码 0xA001

            for (int i = 0; i < bytes.Length; i++)
            {
                crcRegister_L = (byte)(crcRegister_L ^ bytes[i]);

                for (int j = 0; j < 8; j++)
                {
                    byte tempCRC_H = crcRegister_H;
                    byte tempCRC_L = crcRegister_L;

                    crcRegister_H = (byte)(crcRegister_H >> 1);
                    crcRegister_L = (byte)(crcRegister_L >> 1);
                    // 高位右移前最后 1 位应该是低位右移后的第 1 位：如果高位最后一位为 1 则低位右移后前面补 1
                    if ((tempCRC_H & 0x01) == 0x01)
                    {
                        crcRegister_L = (byte)(crcRegister_L | 0x80);
                    }

                    if ((tempCRC_L & 0x01) == 0x01)
                    {
                        crcRegister_H = (byte)(crcRegister_H ^ polynomialCode_H);
                        crcRegister_L = (byte)(crcRegister_L ^ polynomialCode_L);
                    }
                }
            }

            return new byte[] { crcRegister_L, crcRegister_H };
        }

        public static string CRCCheck(string val)
        {
            val = val.TrimEnd(' ');
            string[] spva = val.Split(' ');
            byte[] bufData = new byte[spva.Length + 2];
            bufData = ToBytesCRC(val);
            ushort CRC = 0xffff;
            ushort POLYNOMIAL = 0xa001;
            for (int i = 0; i < bufData.Length - 2; i++)
            {
                CRC ^= bufData[i];
                for (int j = 0; j < 8; j++)
                {
                    if ((CRC & 0x0001) != 0)
                    {
                        CRC >>= 1;
                        CRC ^= POLYNOMIAL;
                    }
                    else
                    {
                        CRC >>= 1;
                    }
                }
            }
            return ToHex(System.BitConverter.GetBytes(CRC));
        }
        /// <summary>
        /// 例如把如下字符串转换成字节数组
        /// AA AA AA AA 0A 00 68 00 06 03 04 54 21 28 22 E5 F3 16 BB BB BB BB   转换为字节数组
        /// </summary>
        /// <param name="hex">十六进制字符串</param>
        /// <returns></returns>
        public static byte[] ToBytesCRC(string hex)
        {
            string[] temp = hex.Split(' ');
            byte[] b = new byte[temp.Length + 2];

            for (int i = 0; i < temp.Length; i++)
            {
                b[i] = Convert.ToByte(temp[i], 16);
            }

            return b;
        }
        /// <summary>
        /// 将字节数据转换为十六进制字符串，中间用 “ ”分割 如：AA AA AA AA 0A 00 68 00 06 03 04 54 21 28 22 E5 F3 16 BB BB BB BB
        /// </summary>
        /// <param name="vars">要转换的字节数组</param>
        /// <returns></returns>
        public static String ToHex(byte[] vars)
        {
            return BitConverter.ToString(vars).Replace('-', ' ').Trim();
        }
        public static String ToString(ushort[] vars)
        {
            var lst = new List<string>();
            foreach (var v in vars) {
                lst.Add(v.ToString());
            }
            return string.Join(" ", lst);
        }
        public static String ToString(bool[] vars)
        {
            var lst = new List<string>();
            foreach (var v in vars)
            {
                lst.Add(v?"1":"0");
            }
            return string.Join(" ", lst);
        }
        public static bool BoolParse(string b)
        {
            b = b.Replace("1", "true").Replace("0", "false");
            return bool.Parse(b);
        }
    }
}
